[BLKTAP]: Fix potential grant entry leaks on error
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 20 Oct 2006 08:28:31 +0000 (09:28 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 20 Oct 2006 08:28:31 +0000 (09:28 +0100)
As it stands grant entries for the actual data are mapped in bulk.
If one of the earlier entries fail to be mapped, it can cause all
subsequent entries to be leaked if they were successfully mapped.

This patch changes it so that we will continue to reap grant entries
even when an error is detected.

There is still a potential leak if create_lookup_pte_addr fails
in fast_flush_area.  This leak is not affected by this patch.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c

index 0adaa7b5d8ac03250c81d9bc8bc77b60275b5d05..1fcf56fc412fa96fee368b660398aed572bddd32 100644 (file)
@@ -845,28 +845,29 @@ static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int
                uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
 
                khandle = &pending_handle(mmap_idx, k_idx, i);
-               if (BLKTAP_INVALID_HANDLE(khandle)) {
-                       WPRINTK("BLKTAP_INVALID_HANDLE\n");
-                       continue;
+
+               if (khandle->kernel != 0xFFFF) {
+                       gnttab_set_unmap_op(&unmap[invcount],
+                                           idx_to_kaddr(mmap_idx, k_idx, i),
+                                           GNTMAP_host_map, khandle->kernel);
+                       invcount++;
                }
-               gnttab_set_unmap_op(&unmap[invcount], 
-                                   idx_to_kaddr(mmap_idx, k_idx, i), 
-                                   GNTMAP_host_map, khandle->kernel);
-               invcount++;
-
-               if (create_lookup_pte_addr(
-                   info->vma->vm_mm,
-                   MMAP_VADDR(info->user_vstart, u_idx, i), 
-                   &ptep) !=0) {
-                       WPRINTK("Couldn't get a pte addr!\n");
-                       return;
+
+               if (khandle->user != 0xFFFF) {
+                       if (create_lookup_pte_addr(
+                               info->vma->vm_mm,
+                               MMAP_VADDR(info->user_vstart, u_idx, i),
+                               &ptep) !=0) {
+                               WPRINTK("Couldn't get a pte addr!\n");
+                               return;
+                       }
+
+                       gnttab_set_unmap_op(&unmap[invcount],
+                                           ptep, GNTMAP_host_map,
+                                           khandle->user);
+                       invcount++;
                }
 
-               gnttab_set_unmap_op(&unmap[invcount], 
-                       ptep, GNTMAP_host_map,
-                       khandle->user);
-               invcount++;
-            
                BLKTAP_INVALIDATE_HANDLE(khandle);
        }
        ret = HYPERVISOR_grant_table_op(
@@ -1223,19 +1224,25 @@ static void dispatch_rw_block_io(blkif_t *blkif,
                if (unlikely(map[i].status != 0)) {
                        WPRINTK("invalid kernel buffer -- "
                                "could not remap it\n");
-                       goto fail_flush;
+                       ret |= 1;
+                       map[i].handle = 0xFFFF;
                }
 
                if (unlikely(map[i+1].status != 0)) {
                        WPRINTK("invalid user buffer -- "
                                "could not remap it\n");
-                       goto fail_flush;
+                       ret |= 1;
+                       map[i+1].handle = 0xFFFF;
                }
 
                pending_handle(mmap_idx, pending_idx, i/2).kernel 
                        = map[i].handle;
                pending_handle(mmap_idx, pending_idx, i/2).user   
                        = map[i+1].handle;
+
+               if (ret)
+                       continue;
+
                set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
                        FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
                offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
@@ -1243,6 +1250,10 @@ static void dispatch_rw_block_io(blkif_t *blkif,
                ((struct page **)info->vma->vm_private_data)[offset] =
                        pg;
        }
+
+       if (ret)
+               goto fail_flush;
+
        /* Mark mapped pages as reserved: */
        for (i = 0; i < req->nr_segments; i++) {
                unsigned long kvaddr;